import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'

const getFilenameByHeaders = (headers: AxiosResponse['headers'] | undefined): string | undefined => {
  if (!headers) return

  let disposition: string
  if (headers instanceof axios.AxiosHeaders) {
    disposition = `${headers.get('content-disposition') || ''}`
  } else {
    disposition = `${headers['content-disposition'] || ''}`
  }

  if (disposition) {
    const list = disposition.split(';').map(v => v.split('=')) as [string, string | undefined][]
    for (const [key, val] of list) {
      if (!val) continue
      if (/^filename\*?$/i.test(key.replace(/\s/g, ''))) {
        const matches = val.trim().match(/^"?\s*(utf-8\s*'.*?')?(.+?)"?$/i)
        if (matches) {
          const name = matches[2].trim()
          if (name) {
            return decodeURIComponent(matches[2].trim())
          }
        }
      }
    }
  }
}

/** 下载 blob */
export const downloadBlob = (blob: Blob, filename: string): void => {
  const url = window.URL.createObjectURL(blob)
  const anchor = document.createElement('a')
  anchor.style.display = 'none'
  anchor.href = url
  anchor.setAttribute('download', filename)

  document.body.appendChild(anchor)
  setTimeout(() => {
    anchor.click()
    document.body.removeChild(anchor)
    setTimeout(() => window.URL.revokeObjectURL(url), 250)
  }, 66)
}

/** 通过接口下载 */
export const downloadFromServer = async ({
  defaultFilename,
  ...axiosRequestConfig
}: {
  method: 'get' | 'GET' | 'post' | 'POST'
  url: string
  defaultFilename: string
} & AxiosRequestConfig): Promise<boolean> => {
  const handleDownload = (data: unknown, headers: AxiosResponse['headers'] | undefined) => {
    if (data instanceof Blob) {
      downloadBlob(data, getFilenameByHeaders(headers) || defaultFilename)
      return Promise.resolve(true)
    }
    return Promise.reject(new Error())
  }

  try {
    const { data, headers } = await axios({
      $hideErrMsg: $res => $res instanceof Blob,
      ...axiosRequestConfig,
      responseType: 'blob',
    })
    return handleDownload(data, headers)
  } catch (err) {
    if (axios.isAxiosError(err)) {
      return handleDownload(err.response?.data, err.response?.headers)
    }
    throw err
  }
}
